﻿using System;
using System.IO;
using System.Data;
using System.Data.SqlClient;
using System.Collections.Generic;
using System.Configuration;
using System.Text;
using System.Text.RegularExpressions;
using System.Net;
using System.Web;

[assembly:CLSCompliant(true)]

namespace WebMsg
{
    public abstract class WebMsg
    {
        protected String authURL;
        protected String messageURL;
        protected String balanceURL;

        protected String User { get { return _user; } }
        protected String Pass { get { return _pass; } }
        protected bool HasCredentials { get; private set; }

        protected readonly Queue<Sms> QueuedMessages;
        protected Dictionary<String, ResultCodes> Results;
        
        // Public Properties
        public Boolean CustomFrom { get; set; }
        public String From { get; set; }

        // Abstract Methods
        public abstract String GetCreditsRemaining();
        protected abstract void AddResults();

        // Event Handlers
        internal delegate void CredentialsUpdatedHandler(object sender, EventArgs args);
        internal event CredentialsUpdatedHandler CredentialsUpdated;

        protected WebMsg()
        {
            this.QueuedMessages = new Queue<Sms>();
            this.Results = new Dictionary<string, ResultCodes>();
            AddResults();
        }

        public void QueueMessage(Sms message)
        {
            QueuedMessages.Enqueue(message);
        }

        public void QueueMessage(TelAddress from, TelAddress to, String body)
        {
            QueueMessage(new Sms(from, to, body));
        }

        public void QueueMessage(String from, String to, String body)
        {
            if (!CustomFrom)
                from = "0123456789";

            TelAddress f = new TelAddress(from, from);
            TelAddress t = new TelAddress(to, to);

            QueueMessage(f, t, body);
        }

        public virtual void SetCredentials(String username, String password)
        {
            _user = username;
            _pass = password;
            HasCredentials = true;

            CredentialsUpdated(this, null);
        }

        public void Send()
        {
            foreach (Sms message in QueuedMessages)
            {
                if ((message.Result = this.ParseResult(this.SendMessage(message))) == ResultCodes.Success)
                {
                    message.Sent = DateTime.Now;
                }
            }
        }

        protected abstract String SendMessage(Sms message);

        protected virtual String SendMessage(Sms message, Uri address)
        {
            String result;
            HttpWebRequest objRequest = (HttpWebRequest)WebRequest.Create(address);
            objRequest.CookieContainer = new CookieContainer();
            objRequest.Method = "GET";
            objRequest.ContentType = "application/x-www-form-urlencoded";

            try
            {
                using (HttpWebResponse objResponse = (HttpWebResponse)objRequest.GetResponse())
                {
                    using (StreamReader sr = new StreamReader(objResponse.GetResponseStream()))
                    {
                        result = sr.ReadToEnd();
                        sr.Close();
                    }
                }
            }
            catch (HttpException ex)
            {
                return ex.Message;
            }

            return result;
        }

        public static string GetCreditsRemainingRaw(String url)
        {
            string result = "Error";

            Uri address = new Uri(url);

            try
            {
                HttpWebRequest req = (HttpWebRequest)WebRequest.Create(address);
                using (HttpWebResponse resp = (HttpWebResponse)req.GetResponse())
                {
                    using (Stream st = resp.GetResponseStream())
                    {
                        using (StreamReader sr = new StreamReader(st))
                        {
                            result = sr.ReadToEnd();
                        }
                    }
                }
            }
            catch { }

            return result;
        }

        protected virtual ResultCodes ParseResult(String result)
        {
            if (String.IsNullOrWhiteSpace(result))
                throw new ArgumentNullException("result");

            if (Results.ContainsKey(result))
                return Results[result];
            else
                return ResultCodes.ErrorUnknown;
        }

        // Gets credentials from database
        public void SetCredentials(String DBConnectionString)
        {
            if (ConfigurationManager.ConnectionStrings[DBConnectionString] == null)
                throw new ArgumentException("Invalid database connection string.");

            using (SqlConnection db = new SqlConnection(ConfigurationManager.ConnectionStrings[DBConnectionString].ToString()))
            {
                using (SqlCommand cmd = new SqlCommand("SMSConfigSelect", db))
                {
                    cmd.CommandType = CommandType.StoredProcedure;

                    try
                    {
                        cmd.Connection.Open();
                        SqlDataReader reader = cmd.ExecuteReader();

                        if (reader == null)
                            throw new DataException("SMS credentials could not be retrieved.");

                        if (reader.HasRows)
                        {
                            reader.Read();
                            SetCredentials(reader[0].ToString(), reader[1].ToString());
                            if (String.IsNullOrEmpty(this.From)) this.From = reader[2].ToString();
                        }
                        else
                        {
                            throw new DataException("SMS credentials could not be retrieved.");
                        }
                    }
                    catch
                    {
                        throw new DataException("SMS credentials could not be retrieved.");
                    }
                    finally
                    {
                        cmd.Connection.Close();
                    }
                }
            }
        }

        public static WebMsg CreateWebMsg(String provider)
        {
            if (String.IsNullOrWhiteSpace(provider))
                throw new ArgumentNullException("provider");

            if (provider.Equals("Bulk SMS"))
            {
                return new BulkSms();
            }
            else if (provider.Equals("SMS Global"))
            {
                return new SmsGlobal();
            }
            else if (provider.Equals("MyNetFone"))
            {
                return new MyNetFone();
            }
            else if (provider.Equals("Net Onboard"))
            {
                return new NetOnboard();
            }
            else
            {
                throw new ArgumentException("Invalid provider specified.");
            }
        }

        // SMS message details
        private String _user = "";
        private String _pass = "";
    }
}
